spark saveAsTextFile到s3失败

时间:2016-03-04 18:49:46

标签: amazon-s3 apache-spark

我有一个Spark进程,从S3获取两个输入文件。在工作结束时,我只想用saveAsTextFile方法将结果写回S3。但是,我收到Access Denied错误。

我的政策规则是公开的,以确保我没有任何权限错误:

{
    "Version": "2012-10-17",
    "Id": "Policy1457106962648",
    "Statement": [
        {
            "Sid": "Stmt1457106959104",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::<bucket-name>/*"
        }
    ]
}

我在SparkContext上设置了我的凭据,如下所示:

SparkConf conf = new SparkConf()
                .setAppName("GraphAnalyser")
                .setMaster("local[*]")
                .set("spark.driver.memory", "2G");
                .set("spark.hadoop.fs.s3.awsAccessKeyId", [access-key])
                .set("spark.hadoop.fs.s3n.awsAccessKeyId", [access-key])
                .set("spark.hadoop.fs.s3.awsSecretAccessKey", [secret-key])
                .set("spark.hadoop.fs.s3n.awsSecretAccessKey", [secret-key]);

我使用s3n协议的传递文件URL:

final String SC_NODES_FILE  = "s3n://" + BUCKET_NAME + "/" + NODES_FILE;
final String SC_EDGES_FILE  = "s3n://" + BUCKET_NAME + "/" + EDGES_FILE;
final String SC_OUTPUT_FILE = "s3n://" + BUCKET_NAME + "/output";

请注意,我访问输入文件没有问题。看起来Spark会为输出文件发送HEAD请求,以确保它在尝试保存最终结果之前不存在。因为,s3返回Access Denied而不是Not Found。这可能是Spark抛出异常并退出的原因。

org.apache.hadoop.fs.s3.S3Exception: org.jets3t.service.S3ServiceException: S3 HEAD request failed for '/output.csv' - ResponseCode=403, ResponseMessage=Forbidden

Spark 1.6.0 aws-java-sdk(1.10.58) spark-core_2.10(1.6.0)

感谢您的帮助。非常感谢你。

1 个答案:

答案 0 :(得分:3)

回答我自己的问题

事实证明,我需要s3:ListBucket动作,仅当资源是存储桶本身时才适用,而不是存储桶中的密钥。

在我的原始政策文件中,我有以下资源:

"Resource": "arn:aws:s3:::<bucket-name>/*"

我不得不补充道:

"Resource": "arn:aws:s3:::<bucket-name>/*"

这是我的最终政策文件,对我有用:

{
  "Id": "Policy145712123124123",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt145712812312323",
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::<bucket-name>",
        "arn:aws:s3:::<bucket-name>/*"
      ],
      "Principal": {
        "AWS": [
          "arn:aws:iam::<account-id>:user/<user-name>"
        ]
      }
    }
  ]
}