为什么我为 Amazon S3 存储桶预签名 URL 会在我指定的到期时间之前到期?

Why is my presigned URL for an Amazon S3 bucket expiring before the expiration time that I specified?

我有一段代码发送带有预签名 S3 URL 的邮件,我在 Java 中使用 AWS SDK(1.11.482) 像这样生成邮件:

ZonedDateTime expiration = ZonedDateTime.now();
expiration = expiration.plusDays(7);
GeneratePresignedUrlRequest generatePresignedUrlRequest =  new GeneratePresignedUrlRequest(<Bucket>, <Key>).withMethod(HttpMethod.GET)
    .withExpiration(Date.from(expiration.toInstant()));

AmazonS3 amazonS3Client = AmazonS3ClientBuilder.standard().withRegion(<Region>)
        .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(<AccessKey>, <SecretKey>))).build()

String s3Url = amazonS3Client.generatePresignedUrl(generatePresignedUrlRequest).toString();

但是,它不会在 7 天后过期,而是会在大约 24 小时后过期。奇怪的是,如果我看看实际的 url:

https://<AWS S3 Url>
?X-Amz-Security-Token=<Token>
&X-Amz-Algorithm=AWS4-HMAC-SHA256
&X-Amz-Date=20190117T072701Z
&X-Amz-SignedHeaders=host
&X-Amz-Expires=604799
&X-Amz-Credential=<Credential>aws4_request
&X-Amz-Signature=<Signature>

那么过期时间戳实际上就是我所期望的。但即使在 24 小时后访问它,我也会得到:

<Error>
<Code>ExpiredToken</Code>
<Message>The provided token has expired.</Message>
<Token-0>
FQoGZXIvYXdzEPD//////////wEaDNkjQqZnq1LsP/9OCCKIAtq5Au7PKYSxzcqpwPlTF9DH3oyOrjo2Zft91L1pkCKX5VXHCFPClo0b0V5jo+GaNjHBLNYWN7lrUJm+20hOPURxvP/7ytZ5w5L3kk0DiisDdqPlup4xBUXGAOXqnQrjd7CqV6R0cr+8AD+tEh8QXZFxz//VCYKviFRA3vO/fIimuRq9Os4CACXLuuEU3GDKpDkhoHSN70tgmxMr2xBD6Wlo2UFClSUOt5pNzbSAjgD896fWSqf3C5DbZVAuasK/z2IOAI0OG6N/auOnsBBkLJ23nLvHrjzgnJZaKO/JSaG4PF0jyOphED8fvQ1V5P8xm2gDKT/shv1U1IQLYJjRVzZySdpStZMJfCiwxYDiBQ==
</Token-0>
<RequestId>23CFB9FB0973C599</RequestId>
<HostId>
G4tEmvGfauxHfkcyuGgTDJ+JxAJ4DEO6WPcDwBWkDBMLnw0R1cdTepUFHbIGmSF/FeV/oYnSq7c=
</HostId>
</Error>

注意:访问和密钥与 IAM 用户相关联,没有设置过期时间。

要创建有效期长达 7 天的预签名 URL,请首先将 IAM 用户凭据(访问密钥和秘密访问密钥)指定给您正在使用的 SDK(这似乎是Java AWS SDK 在你的情况下)。然后,使用 AWS 签名版本 4.

生成预签名的 URL

这是 python 中 Boto 的示例:

import boto3
from botocore.client import Config

# Get the service client with sigv4 configured
s3 = boto3.client('s3', config=Config(signature_version='s3v4'))

此外,我知道您提到了它,但您需要确保您使用的凭据直接来自 IAM 用户,而不是来自 IAM 角色,因为他们的令牌每 24-36 小时轮换一次。