AWS S3 Java:d​​oesObjectExist 导致 403:禁止

Posted

技术标签:

【中文标题】AWS S3 Java:d​​oesObjectExist 导致 403:禁止【英文标题】:AWS S3 Java: doesObjectExist results in 403: FORBIDDEN 【发布时间】:2017-10-30 14:11:36 【问题描述】:

我的 Java 程序使用 AWS 开发工具包与 S3 存储桶交互时遇到问题。

这是我用来创建 S3 客户端的代码:

public S3StorageManager(S3Config config) throws StorageException 

   BasicAWSCredentials credentials = new BasicAWSCredentials(myAccessKey(), mySecretKey());
   AWSStaticCredentialsProvider provider = new AWSStaticCredentialsProvider(credentials);

   this.s3Client = AmazonS3ClientBuilder
        .standard()
        .withCredentials(provider)
        .withRegion(myRegion)
        .build();

当我尝试下载文件时,在开始下载之前,我会检查文件是否存在:

s3Client.doesObjectExists(bucketName, objectName);

这是我得到 403: FORBIDDEN 的地方。 奇怪的是,仅当我在同一会话中执行上传之前尝试执行对象存在检查时才会出现此问题。 换句话说,在初始化 s3Client 之后: - 如果我首先尝试检查对象是否存在,则会引发 FORBIDDEN 问题; - 如果我首先执行文件上传,它可以正常工作,之后任何对象存在检查也可以正常工作;

这是我的堆栈跟踪:

com.amazonaws.services.s3.model.AmazonS3Exception: Forbidden (Service: Amazon S3; Status Code: 403; Error Code: 403 Forbidden; Reques
t ID: A23BB805491E411F)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1588) ~[aws-java-sdk-core-1.
11.128.jar:?]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1258) ~[aws-java-sdk-core-1.11
.128.jar:?]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1030) ~[aws-java-sdk-core-1.11.128
.jar:?]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:742) ~[aws-java-sdk-core-1.11.128.jar:
?]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:716) ~[aws-java-sdk-core-1.11.1
28.jar:?]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:699) ~[aws-java-sdk-core-1.11.128.jar:?]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:667) ~[aws-java-sdk-core-1.11.128.jar
:?]
        at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:649) ~[aws-java-sdk-core-1.1
1.128.jar:?]
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:513) ~[aws-java-sdk-core-1.11.128.jar:?]
        at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4169) ~[aws-java-sdk-s3-1.11.128.jar:?]
        at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:4116) ~[aws-java-sdk-s3-1.11.128.jar:?]
        at com.amazonaws.services.s3.AmazonS3Client.getObjectMetadata(AmazonS3Client.java:1237) ~[aws-java-sdk-s3-1.11.128.jar:?]
        at com.amazonaws.services.s3.AmazonS3Client.getObjectMetadata(AmazonS3Client.java:1213) ~[aws-java-sdk-s3-1.11.128.jar:?]
        at com.amazonaws.services.s3.AmazonS3Client.doesObjectExist(AmazonS3Client.java:1272) ~[aws-java-sdk-s3-1.11.128.jar:?]

另一个奇怪的事情是,当我将我的 Java 程序移到 EC2 远程机器上时,所有这些问题都开始了。 如果我在本地机器上执行它,S3 交互工作正常。 但是我不认为问题取决于 IAM 角色,因为我使用的是 AWSStaticCredentialsProvider。

【问题讨论】:

我很确定这是您的“凭证文件”可访问性(那些 myaccesskey() 方法)的问题,只是为了证明,用真正的 accesskey 和安全密钥替换它们。 我在创建 AWSStaticCredentialsProvider 后检查了 provider.getCredentials(),它返回了正确的凭据......所以我猜这些方法是正确的(除了它们可怕的临时名称:P) 当您更改订单、PUT 然后检查是否存在时,这在 EC2 上可以正常工作吗?如果是这样,我们可以得出结论,这不是政策问题。我们可以检查您的完整代码以及您使用的 aws-sdk 版本吗? 我遇到了同样的问题。你有没有找到解决办法? (我使用的是 aws-java-sdk 1.11.170。) 嗨@FullTimeCoderPartTimeSysAdmin。不幸的是,到目前为止我发现的唯一解决方案是在服务器启动时上传一个空文件并立即将其删除。之后,可以执行所有其他 S3 交互。这是一个丑陋的噱头,但它有点工作。 【参考方案1】:

您的凭据可能是正确的,但如果您没有设置正确的 IAM 策略,您仍然会收到 FORBIDDEN。要检查 s3 中的对象,您需要以下内容:


    "Version":"2012-10-17",
    "Statement":[
        
            "Effect":"Allow",
            "Action":[
            "s3:ListBucket"
            ],
            "Resource":["arn:aws:s3:::examplebucket/*"]
        ,
        
            "Effect":"Allow",
            "Action":[
            "s3:GetObject"
            ],
          "Resource":["arn:aws:s3:::examplebucket/*"]
        
    ]

【讨论】:

这仅适用于我的 "Resource":["*"] 用于 "s3:ListBucket" 操作。 (这里的关键是“s3:ListBucket”操作。) ListBucket 的资源必须是桶,而不是文件,即末尾没有“/*”。【参考方案2】:

确保在您发出请求的机器上正确设置了日期时间,否则您将收到 403。

【讨论】:

我在 Windows 上使用 Docker,当我的笔记本电脑从睡眠中恢复时,我经常会遇到时钟漂移。这让我发疯了,感谢您指出正确的方向!【参考方案3】:

您的存储桶需要一个操作“ListBucket”,而不是存储桶中的文件,例如: “行动”: [ “s3:列表桶” ], "资源": "arn:aws:s3:::bucketName", “效果”:“允许”

【讨论】:

【参考方案4】:

我看起来确实像是 IAM 政策问题。 您的本地计算机上的用户策略是什么,而您的 IAM 角色是什么? 对于您的 EC2 实例,当您创建它时,使用“AmazonS3FullAccess”策略创建一个角色,如果它解决了问题,您将删除无用的权限。

【讨论】:

但如果是 IAM 政策问题,为什么它会在我执行上传后“神奇地”消失? ://

以上是关于AWS S3 Java:d​​oesObjectExist 导致 403:禁止的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 aws-java-sdk 从 S3 逐块读取文件

java AWS S3服务器端加密(非KMS)

如何使用 Java 列出存储桶中的所有 AWS S3 对象

java 使用AWS Java SDK构建本地Minio S3客户端

java AWS S3从版本存储桶中删除所有对象

AWS - CORS 无法将文件直接上传到 S3