I want to access a file in an S3 bucket from an API Gateway endpoint.
I have uploaded the file to an S3 bucket with a key: path//filename.txt
(note the empty sub-folder name is intentional)
However, when I issue the following HTTP request:
curl -X GET 'https://api.cloud/v1/files/filename.txt'
The integration fails and returns an XML error. The API Gateway logs state:
Received response. Status: 403, Integration latency: 8 ms
Endpoint response body before transformations:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
...
</Error>
I cannot for the life of me figure out what I am missing.
Am I not allowed to have an API Gateway integration to an S3 object that contains an empty folder in the key?
I have deployed the S3 bucket using CloudFormation, here are some relevant pieces:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
MyBucket:
Type: 'AWS::S3::Bucket'
Properties:
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
CorsConfiguration:
CorsRules:
- AllowedHeaders: ['*']
AllowedMethods: [GET,PUT]
AllowedOrigins: ['*']
ExposedHeaders: [Date]
Id: CORSRules
MaxAge: 3600
BucketReadRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- apigateway.amazonaws.com
Action: 'sts:AssumeRole'
Policies:
- PolicyName: bucket-read
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 's3:GetObject'
Resource: !Join
- '/'
- - !GetAtt MyBucket.Arn
- '*'
I have configured the API Gateway with the following integration (note the %2F
to account for the empty sub-folder name):
paths:
/files/{filename}:
get:
parameters:
- in: path
name: filename
required: true
schema:
type: string
x-amazon-apigateway-integration:
credentials:
Fn::Sub: ${BucketReadRole.Arn}
uri:
Fn::Sub:
- arn:${AWS::Partition}:apigateway:${AWS::Region}:s3:path/${MyBucket}/path/%2F{filename}
- MyBucket:
Fn::ImportValue: MyBucket
responses:
default:
statusCode: "200"
responseParameters:
method.response.header.Content-Length: "integration.response.header.Content-Length"
method.response.header.Content-Type: "integration.response.header.Content-Type"
method.response.header.ETag: "integration.response.header.ETag"
requestParameters:
integration.request.path.filename: "method.request.path.filename"
passthroughBehavior: "when_no_match"
httpMethod: "GET"
type: "aws"
I came across this issue due to a +
in the filename (S3 object key). When trying to download the file via the ApiGateway S3 integration it was URL encoded to %2B
and I saw the SignatureDoesNotMatch
error. To fix I removed the +
from the S3 key.
Your x-amazon-apigateway-integration.uri
configuration has a %2F
encoded slash that looks out of place:
${AWS::Partition}:apigateway:${AWS::Region}:s3:path/%2F{filename}
I suspect removing this slash will also fix your problem.