我想从 Java Elastic Beanstalk 应用程序访问 AWS S3 存储桶中的文件。
应用程序(Spring Boot 微服务)在本地运行时运行良好。列出、读取和写入存储桶中的对象没有问题。
这就是我构建 S3 客户端的方式:
AmazonS3 s3client = AmazonS3ClientBuilder
.standard()
.withRegion(Regions.EU_WEST_2)
.build();
这就是我列出存储桶中对象的方式:
s3client.listObjects(<BUCKET_NAME>).getObjectSummaries();
在 IAM 中我创建了一个具有权限的角色:
在 Elastic Beanstalk 环境中,我已将其设置为服务角色和 EC2 实例配置文件。
但是,当我部署应用程序时,对存储桶的访问失败:
com.amazonaws.services.s3.model.AmazonS3Exception:存储桶位于 该区域:eu-central-1。请使用该区域重试请求 (服务:Amazon S3;状态代码:301;
此错误消息不正确。根据bucket概览,该bucket位于AWS Region 欧洲(伦敦)eu-west-2
我已尝试遵循建议并使用它建议的区域:
AmazonS3 s3client = AmazonS3ClientBuilder
.standard()
.withRegion(Regions.EU_CENTRAL_1)
.build();
然后返回拒绝访问错误消息:
由以下原因引起:com.amazonaws.services.s3.model.AmazonS3Exception:访问 被拒绝(服务:Amazon S3;状态代码:403;错误代码: 访问被拒绝;
Elastic Beanstalk 应用程序的域显示它正在与其尝试访问的 S3 存储桶在同一区域中运行:
.eu-west-2.elasticbeanstalk.com
为了清楚起见,该存储桶是我通过 AWS S3 控制台使用我的帐户创建的。我的帐户是该存储桶的所有者。该应用程序也是我通过 Elastic Beanstalk 控制台使用我的帐户创建的。我还有其他 Java Elastic Beanstalk 应用程序,部署后可以毫无问题地访问 S3 存储桶,这意味着不存在帐户范围内的原因。
我还尝试了以下操作,这也会导致访问被拒绝错误响应。
AmazonS3 s3client = AmazonS3ClientBuilder
.standard()
.enableForceGlobalBucketAccess()
.build();
如何让该应用程序在部署后访问 S3?
事实证明,由于缺少环境变量导致使用默认存储桶名称,我没有访问我认为的存储桶。不幸的是,默认存储桶名称实际上是由不同区域的不同 AWS 账户注册的真实存储桶。因此,AWS 错误消息是正确的,但如果错误消息包含拒绝访问的存储桶的名称,问题会更加明显。
环境变量是在本地定义的,因此不会影响我的本地开发计算机 - 只有部署的实例受到影响。请务必在调用 SDK 之前打印存储桶名称,以确保拒绝访问的“资源”符合预期。