LocalStack环境下AWS S3预签名GET URL报InvalidAccessKeyId错误
问题描述
在LocalStack本地AWS环境中,普通的S3上传、下载图片功能正常,但使用带有效期的预签名URL(Presigned URLs)实现下载时,点击生成的URL会返回以下错误:
<Error> <Code>InvalidAccessKeyId</Code> <Message> The AWS Access Key Id you provided does not exist in our records. </Message> <AWSAccessKeyId>test</AWSAccessKeyId> </Error>
生成预签名URL的代码如下:
protected URL generatePresignedURL(String objectKey) { // object key example: "Screen Shot 2022-07-04 at 11.29.59 PM (3).png" S3Presigner presigner = S3Presigner.create(); GetObjectRequest objectRequest = buildGetRequest(objectKey); GetObjectPresignRequest presignedRequest = buildPresignedGetRequest(objectRequest); PresignedGetObjectRequest presignedGetObjectRequest = presigner.presignGetObject(presignedRequest); System.out.println("Presigned URL: " + presignedGetObjectRequest.url()); return presignedGetObjectRequest.url(); } protected GetObjectRequest buildGetRequest(String objectKey) { return GetObjectRequest.builder() .bucket(bucketName) .key(objectKey) .build(); } protected GetObjectPresignRequest buildPresignedGetRequest(GetObjectRequest objectRequest) { // Create a GetObjectPresignRequest from a GetObjectRequest to specify the signature duration return GetObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(5)) .getObjectRequest(objectRequest) .build(); }
Docker Compose中LocalStack的S3配置:
s3-local: container_name: "s3-local" image: localstack/localstack ports: - "127.0.0.1:8008:4566" # LocalStack Gateway environment: - SERVICES=s3 - AWS_ACCESS_KEY_ID=test - AWS_SECRET_ACCESS_KEY=test - START_WEB=0 - DEBUG=0
创建S3桶的命令:
aws s3 mb s3://$LOCAL_S3_BUCKET_NAME --endpoint-url=$LOCAL_S3_SERVICE_ENDPOINT
请问是否需要对S3Presigner对象进行额外配置?
解决方案
需要对S3Presigner进行额外配置,适配LocalStack的本地环境,具体调整如下:
指定LocalStack端点与区域
默认S3Presigner会连接AWS官方S3服务,必须显式配置LocalStack的端点URL(如http://localhost:8008),同时指定一个有效区域(LocalStack对区域要求宽松,比如us-east-1即可)。配置匹配的凭证提供者
虽然LocalStack允许任意凭证,但需确保S3Presigner使用的凭证与LocalStack配置的test/test一致,避免签名验证失败。
修改后的生成预签名URL方法示例:
protected URL generatePresignedURL(String objectKey) { // 配置LocalStack端点和区域 S3ClientConfiguration clientConfig = S3ClientConfiguration.builder() .endpointOverride(URI.create("http://localhost:8008")) .region(Region.US_EAST_1) .build(); // 配置凭证 AwsCredentials credentials = AwsBasicCredentials.create("test", "test"); AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(credentials); // 创建配置好的S3Presigner S3Presigner presigner = S3Presigner.builder() .credentialsProvider(credentialsProvider) .clientConfiguration(clientConfig) .build(); GetObjectRequest objectRequest = buildGetRequest(objectKey); GetObjectPresignRequest presignedRequest = buildPresignedGetRequest(objectRequest); PresignedGetObjectRequest presignedGetObjectRequest = presigner.presignGetObject(presignedRequest); System.out.println("Presigned URL: " + presignedGetObjectRequest.url()); return presignedGetObjectRequest.url(); }
- 额外注意事项
- 若LocalStack端点不是
localhost:8008,替换为实际的$LOCAL_S3_SERVICE_ENDPOINT值; - 确保生成预签名URL时使用的桶名与创建的桶名完全一致;
- LocalStack的S3处理预签名URL时,要求客户端签名时使用匹配的端点,否则会触发凭证验证错误。
- 若LocalStack端点不是
内容的提问来源于stack exchange,提问作者drfalcoew
相关产品推荐
相关产品推荐

