This is a very interesting question!
At first, I thought it is clearly documented in the S3 docs that X-Amz-Expires
is supported by all services (including API Gateway). [1][2]
After some more research, it turned out that it is not so clear at all if services other than S3 support the X-Amz-Expires
parameter.
There are various sources claiming that only S3 is respecting the parameter. The following is a statement by an AWS employee working on the aws-sdk for go:
The expires time is only relevant for the S3 service. Other services have their own fixed expiration time. Generally this is 15 minutes, but it looks like IoT data service uses a 5 minute expiration time. [3]
They followed up with:
The SDK doesn't have any metadata data available providing which services do or do not use the expiry value. [4]
Then adding a note into the corresponding source code on GitHub:
All other AWS services will use a fixed expiration time of 15 minutes. [5]
There are a ton of examples that show that AWS is using the parameter for the S3 service, e.g. [1][6].
However, there are also examples from AWS docs that show the use of the parameter for the IAM service, e.g. [7][8].
That is very confusing.
There is a comment by an SDE at AWS which is dated back to 2018 in which he makes the same confusing observation [9]:
If S3 is the only service that supports this header I agree that the SDK's documentation should be updated to reflect that - including a note in the description for this header in S3's SigV4 documentation stating that this header is exclusive to presigned URLs for this service would also be helpful.
FWIW I spoke to some folks from AWS Auth and the only service they know of using the header is S3 (interesting that you found a code sample using IAM). They suggested that the 15 minute expiration for STS presigned URLs would not be changing.
Another former AWS employee further noticed:
I was able to reproduce this behavior both on the AWS SDKs for Go and PHP with presigned URLs for EC2, IAM, STS, and Route 53. The only service I observed that invalidated a presigned URL after the time specified in the "x-amz-expires" header (instead of the default 15 minutes) was S3.
Thus, I guess it is not possible to increase pre-signed link validity duration for API Gateway access. I think that AWS did not design the signature signing algorithm to support your use case. I think that the S3 presigned URL action is one of the rare exceptions for which AWS allows an extended expiry period.
When looking at their motivation behind creating the signing algorithm the way it is, I noticed that they try to minimize the attack surface for replay attacks:
Protect against potential replay attacks
In most cases, a request must reach AWS within five minutes of the time stamp in the request. Otherwise, AWS denies the request. [10]
There are some more resources [11][12] that lead to the conclusion that letting customers choose lengthy expiry values would undermine the original security purpose of that parameter.
I think there is no generic way to create a presigned URL towards an AWS service's REST API and execute it far in the future.
If I were in your place, I would implement a custom authentication strategy using JWTs and API Gateway Lambda authorizers. [13]
That way you can control the signing algorithm and particulary its expiration time on your own. I want to add that JWTs are URL-safe in the same way AWS signature query string parameters are. [14]
[1] https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
[2] https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html
[3] https://github.com/aws/aws-sdk-go/issues/2304#issuecomment-441755864
[4] https://github.com/aws/aws-sdk-go/issues/2304#issuecomment-441758599
[5] https://github.com/aws/aws-sdk-go/blob/6212dfa8032336d438c526c086918c8d2ceb6432/aws/request/request.go#L310
[6] https://github.com/mhart/aws4/blob/master/aws4.js#L130
[7] https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
[8] https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html
[9] https://github.com/aws/aws-sdk-go/issues/2167#issuecomment-428764319
[10] https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html
[11] https://aws.amazon.com/de/articles/making-secure-requests-to-amazon-web-services/?nc1=h_ls (section "Replay Attacks")
[12] https://stackoverflow.com/a/12267408/10473469
[13] https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html
[14] https://stackoverflow.com/a/56273952/10473469