AWS S3 V2预签名URL提前过期:X-Amz-Security-Token失效求助
解决S3 Signature V2预签名URL提前过期的问题
我来帮你拆解问题根源并给出可行的解决方案:
为什么你的URL会1天就过期?
你遇到的问题其实是两个限制叠加导致的:
- S3预签名URL的固有上限:不管是Signature V2还是V4,S3原生预签名URL的最大有效时长都是7天(604800秒)——你设置的
2592000(30天)已经超出了这个限制,AWS会自动截断到7天,但这还不是你1天就失效的直接原因。 - Lambda临时凭证的有效期限制:你的Lambda函数用的是IAM角色的临时安全凭证,这类凭证默认有效期只有1小时,最多能延长到12小时(通过IAM角色配置)。预签名URL的有效期绝对不能超过生成它的凭证的有效期——哪怕你设了7天的Expires,一旦Lambda的临时凭证过期,URL就会直接失效。你看到的1天过期,大概率是你的IAM角色会话时长被配置成了24小时,但这依然远达不到30天的需求。
要实现1个月有效期的访问链接,该怎么做?
因为S3原生预签名URL最长只能到7天,要实现30天的有效期,有两个方向可选:
方案1:改用CloudFront签名URL(推荐,支持最长1年有效期)
这是AWS官方推荐的长期访问S3资源的方案,步骤大概是:
- 创建CloudFront分发,把源指向你的S3存储桶,配置好缓存规则和访问控制(比如限制只有签名URL能访问)。
- 在IAM中创建一个专门用于签名CloudFront URL的身份(可以用IAM用户的长期凭证,或者用角色生成临时凭证——不过CloudFront签名支持的临时凭证最长也能到12小时,你可以定期生成新的URL)。
- 用AWS SDK生成CloudFront签名URL,把
Expires设为30天后的UNIX时间戳(注意这里是具体的时间点,不是秒数)。
方案2:临时优化Lambda凭证(仅能延长到12小时内,不满足30天需求)
如果你的需求可以妥协到12小时内的有效期,可以按以下步骤调整:
- 打开IAM控制台,找到Lambda关联的角色,编辑它的信任策略,添加允许更长会话时长的条件:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "NumericLessThanEquals": { "sts:DurationSeconds": 43200 } } } ] } - 在该角色的“信任关系”标签页,把
MaxSessionDuration改成43200秒(也就是12小时)。 - 修改Lambda代码,主动获取长时长的临时凭证来生成预签名URL:
这里要注意:const AWS = require('aws-sdk'); async function getLongLivedCredentials() { const sts = new AWS.STS(); const roleArn = 'arn:aws:iam::你的账号ID:role/你的Lambda角色名'; const params = { RoleArn: roleArn, RoleSessionName: 'long-lived-s3-session', DurationSeconds: 43200 // 不能超过角色设置的MaxSessionDuration }; const data = await sts.assumeRole(params).promise(); return { accessKeyId: data.Credentials.AccessKeyId, secretAccessKey: data.Credentials.SecretAccessKey, sessionToken: data.Credentials.SessionToken }; } exports.handler = async (event) => { const creds = await getLongLivedCredentials(); const s3 = new AWS.S3({ signatureVersion: 'v2', region: 'eu-west-1', credentials: creds }); const bucketParam = { Bucket: 'test-bucket', Key: 'testFile-1111-2222', Expires: 43200 // 必须小于等于凭证的有效期 }; const signedUrl = s3.getSignedUrl('getObject', bucketParam); return { signedUrl }; };Expires的值必须小于等于你获取的凭证的有效期,否则URL还是会在凭证过期时失效。
重要提醒
- 绝对不要用长期IAM用户凭证来生成S3预签名URL——长期凭证一旦泄露,你的存储桶安全会面临极大风险。
- CloudFront签名URL不仅支持更长的有效期,还能加IP限制、自定义访问策略等额外安全控制,是长期访问S3资源的最佳实践。
内容的提问来源于stack exchange,提问作者StrawHat
相关产品推荐
相关产品推荐

