import * as cdk from '@aws-cdk/core' ; import * as apigw from "@aws-cdk/aws-apigateway" ; import * as iam from "@aws-cdk/aws-iam" ; export class ApigwS3CdkStack extends cdk . Stack { public readonly apiGatewayRole : iam . Role ; constructor ( scope , id , props ? ) { super ( scope , id , props ) ; const restApi = new apigw . RestApi ( this , 'S3ObjectsApi' , { restApiName : 'S3 Proxy Service' , description : "S3 Actions Proxy API" , endpointConfiguration : { types : [ apigw . EndpointType . EDGE ] } , binaryMediaTypes : [ 'application/octet-stream' , 'image/jpeg' ] } ) ; const bucketResource = restApi . root . addResource ( "{folder}" ) ; const bucketItemResource = bucketResource . addResource ( "{item}" ) ; this . apiGatewayRole = new iam . Role ( this , 'api-gateway-role' , { assumedBy : new iam . ServicePrincipal ( 'apigateway.amazonaws.com' ) } ) ; this . addActionToPolicy ( "s3:ListAllMyBuckets" ) ; const listMyBucketsIntegration = new apigw . AwsIntegration ( { service : "s3" , region : "us-east-1" , path : '/' , integrationHttpMethod : "GET" , options : { credentialsRole : this . apiGatewayRole , passthroughBehavior : apigw . PassthroughBehavior . WHEN_NO_TEMPLATES , integrationResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : 'integration.response.header.Content-Type' } } ] } } ) ; const listMyBucketsMethodOptions = { authorizationType : apigw . AuthorizationType . IAM , methodResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : true } } ] } ; restApi . root . addMethod ( "GET" , listMyBucketsIntegration , listMyBucketsMethodOptions ) ; this . addActionToPolicy ( "s3:ListBucket" ) ; const listBucketIntegration = new apigw . AwsIntegration ( { service : "s3" , region : "us-east-1" , path : '{bucket}' , integrationHttpMethod : "GET" , options : { credentialsRole : this . apiGatewayRole , passthroughBehavior : apigw . PassthroughBehavior . WHEN_NO_TEMPLATES , requestParameters : { 'integration.request.path.bucket' : 'method.request.path.folder' } , integrationResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : 'integration.response.header.Content-Type' } } ] } } ) ; const listBucketMethodOptions = { authorizationType : apigw . AuthorizationType . IAM , requestParameters : { 'method.request.path.folder' : true } , methodResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : true } } ] } ; bucketResource . addMethod ( "GET" , listBucketIntegration , listBucketMethodOptions ) ; this . addActionToPolicy ( "s3:GetObject" ) ; const getObjectMetadataIntegration = new apigw . AwsIntegration ( { service : "s3" , region : "us-east-1" , path : '{bucket}/{object}' , integrationHttpMethod : "HEAD" , options : { credentialsRole : this . apiGatewayRole , passthroughBehavior : apigw . PassthroughBehavior . WHEN_NO_TEMPLATES , requestParameters : { 'integration.request.path.bucket' : 'method.request.path.folder' , 'integration.request.path.object' : 'method.request.path.item' , 'integration.request.header.Accept' : 'method.request.header.Accept' } , integrationResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : 'integration.response.header.Content-Type' } } ] } } ) ; const getObjectMetadataMethodOptions = { authorizationType : apigw . AuthorizationType . IAM , requestParameters : { 'method.request.path.folder' : true , 'method.request.path.item' : true , 'method.request.header.Accept' : true } , methodResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : true } } ] } ; bucketItemResource . addMethod ( "HEAD" , getObjectMetadataIntegration , getObjectMetadataMethodOptions ) ; this . addActionToPolicy ( "s3:GetObject" ) ; const getObjectIntegration = new apigw . AwsIntegration ( { service : "s3" , region : "us-east-1" , path : '{bucket}/{object}' , integrationHttpMethod : "GET" , options : { credentialsRole : this . apiGatewayRole , passthroughBehavior : apigw . PassthroughBehavior . WHEN_NO_TEMPLATES , requestParameters : { 'integration.request.path.bucket' : 'method.request.path.folder' , 'integration.request.path.object' : 'method.request.path.item' , 'integration.request.header.Accept' : 'method.request.header.Accept' } , integrationResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : 'integration.response.header.Content-Type' } } ] } } ) ; const getObjectMethodOptions = { authorizationType : apigw . AuthorizationType . IAM , requestParameters : { 'method.request.path.folder' : true , 'method.request.path.item' : true , 'method.request.header.Accept' : true } , methodResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : true } } ] } ; bucketItemResource . addMethod ( "GET" , getObjectIntegration , getObjectMethodOptions ) ; this . addActionToPolicy ( "s3:PutObject" ) ; const putObjectIntegration = new apigw . AwsIntegration ( { service : "s3" , region : "us-east-1" , path : '{bucket}/{object}' , integrationHttpMethod : "PUT" , options : { credentialsRole : this . apiGatewayRole , passthroughBehavior : apigw . PassthroughBehavior . WHEN_NO_TEMPLATES , requestParameters : { 'integration.request.path.bucket' : 'method.request.path.folder' , 'integration.request.path.object' : 'method.request.path.item' , 'integration.request.header.Accept' : 'method.request.header.Accept' } , integrationResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : 'integration.response.header.Content-Type' } } ] } } ) ; const putObjectMethodOptions = { authorizationType : apigw . AuthorizationType . IAM , requestParameters : { 'method.request.path.folder' : true , 'method.request.path.item' : true , 'method.request.header.Accept' : true , 'method.request.header.Content-Type' : true } , methodResponses : [ { statusCode : '200' , responseParameters : { 'method.response.header.Content-Type' : true } } ] } ; bucketItemResource . addMethod ( "PUT" , putObjectIntegration , putObjectMethodOptions ) ; } private addActionToPolicy ( action ) { this . apiGatewayRole . addToPolicy ( new iam . PolicyStatement ( { resources : [ "*" ] , actions : [ `${ action }` ] } ) ) ; } }