I'm running on an amazon linux instance which has been granted an instance profile, to a iam role with a maximum session duration of 12 hours. According to the documentation, I shouldn't be able to generate a link with an expiration of greater than the remaining time on the session credential:
If you created a presigned URL by using a temporary token, then the URL expires when the token expires. In general, a presigned URL expires when the credential you used to create it is revoked, deleted, or deactivated.
By all appearances, I'm able to create a link with a full 7-day expiration with credentials which are only valid for <12 hours ...but only from the aws cli.
I have these two scripts, one in ruby and the other in bash. Neither do anything with credentials, everything credential related is handled by the AWS tooling. They should produce identical output, but they differ significantly.
#!/usr/bin/env ruby
require "aws-sdk-s3"
require "cgi"
s3_file = Aws::S3::Object.new(ENV['bucket_name'], ENV['object_key'])
url = s3_file.presigned_url(:get, expires_in: 604800)
expiration = CGI::parse(URI.parse(url).query)["X-Amz-Expires"].first
puts expiration
#!/bin/bash
set -euo pipefail
aws s3 presign "s3://$bucket_name/$object_key" --expires-in 604800 \
| tr '&' '\n' \
| awk '/X-Amz-Expires/ { split($0, a, "="); print a[2] }'
Running the scripts:
$ source env_vars.sh
$ ./sh_signed_link_test.sh
604800
$ ./ruby_signed_link_test.rb
21657
The ruby sdk appears to be working correctly, while the aws cli is able to generate a 7 day signed link even though the credentials on the machine expire in ~21657s:
$ date
Wed Jun 11 23:20:59 UTC 2025
$ aws configure export-credentials
{
"Version": 1,
"AccessKeyId": "...",
"SecretAccessKey": "...",
"SessionToken": "...",
"Expiration": "2025-06-12T05:11:28+00:00"
}
The tooling versions:
aws-sdk-s3 (1.189.1)
aws-cli/2.23.11
What is going on? One teammate suggested that the AWS CLI fetches an alternate role, but I feel like that breaks a bunch of assumptions I have about how the AWS toolchain works. Are they right?
Moreover: Is this something I can use to my advantage? I'd like to generate a 7-day link from within a ruby application, but can't due to the sdk behavior demonstrated.
I found the code in the Ruby SDK that is responsible for the discrepancy: https://github.com/aws/aws-sdk-ruby/blob/149b5aded7f245a0e6649e0fadb9e8fd12a28e91/gems/aws-sigv4/lib/aws-sigv4/signer.rb#L767-L780
I think the answer to why there is a discrepancy is most likely that the aws cli just haven't implemented the same logic.
And I don't think you can use this to your advantage. This documentation page explains that the presigned URL will expire when the temporary token expires: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html#PresignedUrl-Expiration
It should be easy to test if you can use it past the temporary credentials expiration, but in all likelihood you will get an error if attempting to use the link after the temporary credentials have expired. But by all means, since it is easy to test you should just do it.