org.apache.hadoop.security.AccessControlException:在EC2上尝试使用hadoop Java API通过s3n URI访问S3 bucket时,权限被拒绝 脚本

org.apache.hadoop.security.AccessControlException:在EC2上尝试使用hadoop Java API通过s3n URI访问S3 bucket时,权限被拒绝 脚本,java,hadoop,amazon-web-services,amazon-s3,tomcat7,Java,Hadoop,Amazon Web Services,Amazon S3,Tomcat7,我创建一个名为“我的角色”的AWS IAM角色,将EC2指定为受信任的实体,即使用信任关系策略文档: { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole"

我创建一个名为“我的角色”的AWS IAM角色,将EC2指定为受信任的实体,即使用信任关系策略文档:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
该角色具有以下策略:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:AbortMultipartUpload",
        "s3:DeleteObject",
        "s3:DeleteObjectVersion",
        "s3:GetBucketAcl",
        "s3:GetBucketCORS",
        "s3:GetBucketLocation",
        "s3:GetBucketLogging",
        "s3:GetBucketNotification",
        "s3:GetBucketPolicy",
        "s3:GetBucketRequestPayment",
        "s3:GetBucketTagging",
        "s3:GetBucketVersioning",
        "s3:GetBucketWebsite",
        "s3:GetLifecycleConfiguration",
        "s3:GetObject",
        "s3:GetObjectAcl",
        "s3:GetObjectTorrent",
        "s3:GetObjectVersion",
        "s3:GetObjectVersionAcl",
        "s3:GetObjectVersionTorrent",
        "s3:ListBucket",
        "s3:ListBucketMultipartUploads",
        "s3:ListBucketVersions",
        "s3:ListMultipartUploadParts",
        "s3:PutObject",
        "s3:PutObjectAcl",
        "s3:PutObjectVersionAcl",
        "s3:RestoreObject"
      ],
      "Resource": [
        "arn:aws:s3:::my-bucket/*"
      ]
    }
  ]
}
我使用AWS CLI从命令行启动了一个EC2实例(Amazon Linux 2014.09.1),将“我的角色”指定为实例配置文件,一切正常。我通过运行以下命令来验证实例是否有效地承担了“我的角色”:

  • curlhttp://169.254.169.254/latest/meta-data/iam/security-credentials/
    查询实例元数据,从中我得到响应
    我的角色
  • curlhttp://169.254.169.254/latest/meta-data/iam/security-credentials/my-role
    我从中获得与“我的角色”关联的临时凭据
此类凭证检索响应的示例如下:

{
  "Code" : "Success",
  "LastUpdated" : "2015-01-19T10:37:35Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "an-access-key-id",
  "SecretAccessKey" : "a-secret-access-key",
  "Token" : "a-token",
  "Expiration" : "2015-01-19T16:47:09Z"
}
  • aws s3 ls s3://my bucket/
    从中我正确地获得了一个列表,其中包含“my bucket”下的第一个子目录。(启动此AMI时,默认情况下会安装和配置AWS CLI。EC2实例和S3 bucket位于同一AWS帐户内)
我在这样的实例上运行/安装了Tomcat7服务器和容器,在这个实例上部署了一个J2EE1.7servlet,没有任何问题

这样的servlet应该使用Hadoop Java API在本地文件系统上从S3 bucket下载文件,特别是从
S3://my bucket/custom path/file.tar.gz
。(请注意,我尝试了hadoop common Artifact2.4.x、2.5.x、2.6.x,但没有任何积极的结果。我将在下面发布使用2.5.x时遇到的异常)

在servlet中,我从上面提到的实例元数据URL中检索新凭据,并使用它们配置我的Hadoop Java API实例:

。。。
路径路径=新路径(“s3n://my bucket/”;
Configuration conf=新配置();
conf.set(“fs.defaultFS”,path.toString());
conf.set(“fs.s3n.awsAccessKeyId”,myAwsAccessKeyId);
conf.set(“fs.s3n.awsSecretAccessKey”,myAwsSecretAccessKey);
conf.set(“fs.s3n.awsSessionToken”,mySessionToken);
...
显然,
myAwsAccessKeyId
myAwsSecretAccessKey
mySessionToken
是我之前用实际值设置的Java变量。 然后,我有效地获得了一个文件系统实例,使用:

FileSystem fs=path.getFileSystem(conf);
我能够检索与文件系统相关的所有配置(fs.getconf().get(key name)),并验证所有配置都是按照假设进行的

问题 我无法使用以下方式下载
s3://my bucket/custom path/file.tar.gz

。。。
copyToLocalFile(false,新路径(Path.toString()+“custom Path/file.tar.gz”)、outputLocalPath);
...
如果我使用hadoop common 2.5.x,我会得到
IOException

org.apache.hadoop.security.AccessControlException:权限被拒绝: s3n://my bucket/custom path/file.tar.gz位于 org.apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.processException(Jets3tNativeFileSystemStore.java:449) 在 org.apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.processException(Jets3tNativeFileSystemStore.java:427) 在 org.apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.handleException(Jets3tNativeFileSystemStore.java:411) 在 org.apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.retrieveMetadata(Jets3tNativeFileSystemStore.java:181) 位于的sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 位于java.lang.reflect.Method.invoke(Method.java:606) org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:187) 在 org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:102) 位于org.apache.hadoop.fs.s3native.$Proxy12.retrieveMetadata(未知 来源)在 org.apache.hadoop.fs.s3native.NativeS3FileSystem.getFileStatus(NativeS3FileSystem.java:467) 位于org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:337) org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:289)位于 org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1968) 在 org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1937)

如果我使用hadoop common 2.4.x,我会得到一个
NullPointerException

java.lang.NullPointerException 位于org.apache.hadoop.fs.s3native.NativeS3FileSystem.getFileStatus(NativeS3FileSystem.java:433) 位于org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:337) 位于org.apache.hadoop.fs.FileUtil.copy(FileUtil.java:289) 位于org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1968) 位于org.apache.hadoop.fs.FileSystem.copyToLocalFile(FileSystem.java:1937)

仅针对记录,如果未设置任何aws凭据,我将获得:

AWS访问密钥ID和机密访问密钥必须指定为 s3n URL的用户名或密码(分别),或通过设置 fs.s3n.awsAccessKeyId或fs.s3n.awsSecretAccessKey属性 (分别)

最后说明
  • 如果我尝试从实例中使用AWS CLI命令从同一个URI(但使用s3代替s3n)下载该文件,则完全没有问题
  • 如果我尝试下载Hadoop发行版(如2.4.1 from),解压缩它,从实例元数据URL检索临时AWS凭据,并尝试运行
    /bin/Hadoop fs-cp s3n://:@my bucket/custom path/file.tar.gz。
    我再次得到一个NPE:
致命的内部错误java.lang.NullPointerException 位于org.apache.hadoop.fs.s3native.NativeS3FileSystem.listStatus(NativeS3FileSystem.java:479) 位于org.apache.hadoop.fs.shell.PathData。
   <property>
     <name>fs.s3.awsAccessKeyId</name>
     <value>ID</value>
   </property>

   <property>
     <name>fs.s3.awsSecretAccessKey</name>
     <value>SECRET</value>
   </property>