EC2实例通过IAM角色生成的S3预签名URL无法正常GET请求
我有一个部署了Node.js和AWS SDK的EC2实例,已为其分配包含EC2全权限、S3全权限等权限的IAM角色。
实例化S3服务的代码如下:
const config: S3.Types.ClientConfiguration = { apiVersion: "2006-03-01", region: "us-east-1", } this.s3 = new S3(config);
随后生成用于展示图片的预签名URL:
const min = expireMin ? expireMin : 20; const expires = 60 * min; // Expires in 20 minutes. const params = { Bucket: "MyBucket", Key: key, Expires: expires, }; const signedUrl = await this.s3.getSignedUrlPromise("getObject", params); return signedUrl;
URL生成看似正常,但使用该URL时会返回400 Bad Request。URL格式为:https://mybucket.s3.amazonaws.com/image-guid/thumbnail.jpg?AWSAccessKeyId=...&Expires=...&Signature=...&x-amz-security-token=..
本地环境使用IAM用户的AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY加载S3服务时可正常访问,但EC2实例通过IAM角色实现时无法正常工作。用Postman请求该URL返回如下错误:
<?xml version="1.0" encoding="UTF-8"?> <Error> <Code>InvalidToken</Code> <Message>The provided token is malformed or otherwise invalid.</Message> <Token-0>...</Token-0> <RequestId>...</RequestId> <HostId>...</HostId> </Error>
请问我遗漏了什么配置?
针对InvalidToken错误,可按以下步骤排查修复:
升级AWS SDK版本
老版本SDK在处理EC2 IAM角色临时凭证时可能存在兼容性问题,建议将aws-sdk(v2)或@aws-sdk/client-s3/@aws-sdk/s3-request-presigner(v3)升级到最新稳定版。确保凭证自动加载正常
EC2实例的IAM角色凭证通过元数据服务自动加载,需确认:- 实例未被安全组/网络ACL阻断访问元数据服务
- 代码中未手动设置
accessKeyId/secretAccessKey,避免覆盖角色凭证
显式指定凭证来源(v2 SDK)
若使用v2 SDK,可强制S3客户端从EC2元数据获取凭证:const s3 = new AWS.S3({ apiVersion: "2006-03-01", region: "us-east-1", credentials: new AWS.EC2MetadataCredentials() });检查IAM角色信任策略
确认角色信任策略允许EC2服务扮演该角色,策略需包含:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }验证临时凭证有效性
在EC2实例执行aws sts get-caller-identity命令,确认返回正确角色信息,同时检查凭证过期时间,避免用过期凭证生成URL。匹配S3桶区域
确保代码中指定的us-east-1区域与实际桶所在区域一致,区域不匹配会导致凭证验证失败。
内容的提问来源于stack exchange,提问作者smb

