Apache spark 使用多个S3帐户运行EMR Spark

Apache spark 使用多个S3帐户运行EMR Spark,apache-spark,amazon-s3,amazon-emr,Apache Spark,Amazon S3,Amazon Emr,我有一份EMR Spark工作,需要在一个帐户上从S3读取数据,然后写入另一个帐户。 我把工作分成两个步骤 从S3读取数据(无需凭据,因为我的EMR群集位于同一帐户中) 读取由步骤1创建的本地HDF中的数据,并将其写入另一个帐户中的S3存储桶 我已尝试设置hadoop配置: sc.hadoopConfiguration.set("fs.s3n.awsAccessKeyId", "<your access key>") sc.hadoopConfiguration.set("fs.s3

我有一份EMR Spark工作,需要在一个帐户上从S3读取数据,然后写入另一个帐户。
我把工作分成两个步骤

  • 从S3读取数据(无需凭据,因为我的EMR群集位于同一帐户中)

  • 读取由步骤1创建的本地HDF中的数据,并将其写入另一个帐户中的S3存储桶

  • 我已尝试设置hadoop配置:

    sc.hadoopConfiguration.set("fs.s3n.awsAccessKeyId", "<your access key>")
    sc.hadoopConfiguration.set("fs.s3n.awsSecretAccessKey","<your secretkey>")
    
    "fs.s3a.credentialsType" -> "AssumeRole",
    "fs.s3a.stsAssumeRole.arn" -> "arn:aws:iam::<<AWSAccount>>:role/<<crossaccount-role>>",
    "fs.s3a.impl" -> "com.databricks.s3a.S3AFileSystem",
    "spark.hadoop.fs.s3a.server-side-encryption-algorithm" -> "aws:kms",
    "spark.hadoop.fs.s3a.server-side-encryption-kms-master-key-id" -> "arn:aws:kms:ap-southeast-2:<<AWSAccount>>:key/<<KMS Key ID>>"
    
    我尝试了集群客户端模式,以及spark shell模式,但运气不佳

    它们中的每一个都返回一个错误:

    ERROR ApplicationMaster: User class threw exception: com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.services.s3.model.AmazonS3Exception: 
    Access Denied
    

    我认为您需要将IAM角色分配给您的计算节点(您可能已经这样做了),然后通过“远程”帐户上的IAM授予跨帐户访问该角色的权限。有关详细信息,请参阅。

    解决方案实际上非常简单

    首先,EMR集群有两个角色:

    • 向EMR服务授予权限的服务角色(
      EMR\u DefaultRole
      ),例如用于启动Amazon EC2实例
    • 附加到群集中启动的EC2实例的EC2角色(
      EMR\u EC2\u DefaultRole
      ),允许其访问AWS凭据(请参阅)
    有关这些角色的说明,请参见:

    因此,集群中启动的每个EC2实例都分配了
    EMR\u EC2\u DefaultRole
    角色,该角色通过实例元数据服务提供临时凭据。(有关如何工作的解释,请参见:)Amazon EMR节点使用这些凭据访问AWS服务,如S3、SNS、SQS、CloudWatch和DynamoDB

    其次,您需要向其他帐户中的Amazon S3 bucket添加权限,以允许通过
    EMR\u EC2\u DefaultRole
    角色进行访问。这可以通过向S3 bucket(此处命名为
    其他帐户bucket
    )添加bucket策略来实现,如下所示:

    {
        "Id": "Policy1",
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "Stmt1",
                "Action": "s3:*",
                "Effect": "Allow",
                "Resource": [
                    "arn:aws:s3:::other-account-bucket",
                    "arn:aws:s3:::other-account-bucket/*"
                ],
                "Principal": {
                    "AWS": [
                        "arn:aws:iam::ACCOUNT-NUMBER:role/EMR_EC2_DefaultRole"
                    ]
                }
            }
        ]
    }
    
    此策略将所有S3权限(
    S3:
    )授予属于与策略中的
    账号匹配的帐户的
    EMR\u EC2\u DefaultRole
    角色,该帐户应为启动EMR群集的帐户。在授予此类权限时要小心——您可能只希望将权限授予
    GetObject
    ,而不是授予所有S3权限

    就这些另一个帐户中的bucket现在将接受来自EMR节点的请求,因为它们正在使用
    EMR\u EC2\u DefaultRole
    角色


    免责声明:我通过在Account-a中创建一个bucket并将权限(如上所示)分配给Account-B中的一个角色来测试上述内容。在Account-B中使用该角色启动了一个EC2实例。我能够通过服务器从EC2实例访问bucket。我没有在EMR中测试它,但是它应该以同样的方式工作。

    使用spark,您也可以使用Ascape角色访问另一个帐户中的s3存储桶,但在另一个帐户中使用IAM角色。这使其他帐户所有者更容易管理为spark作业提供的权限。通过s3 bucket策略管理访问可能是一件痛苦的事情,因为访问权限被分配到多个位置,而不是全部包含在单个IAM角色中

    以下是Hadoop配置的

    sc.hadoopConfiguration.set("fs.s3n.awsAccessKeyId", "<your access key>")
    sc.hadoopConfiguration.set("fs.s3n.awsSecretAccessKey","<your secretkey>")
    
    "fs.s3a.credentialsType" -> "AssumeRole",
    "fs.s3a.stsAssumeRole.arn" -> "arn:aws:iam::<<AWSAccount>>:role/<<crossaccount-role>>",
    "fs.s3a.impl" -> "com.databricks.s3a.S3AFileSystem",
    "spark.hadoop.fs.s3a.server-side-encryption-algorithm" -> "aws:kms",
    "spark.hadoop.fs.s3a.server-side-encryption-kms-master-key-id" -> "arn:aws:kms:ap-southeast-2:<<AWSAccount>>:key/<<KMS Key ID>>"
    

    我们使用databricks进行上述操作,但尚未尝试使用EMR。

    为了控制资源的访问,通常将IAM角色作为标准实践进行管理。假设在您希望访问其他帐户中的资源时使用角色。如果你或你的组织遵循同样的原则,那么你应该遵循。 这里的基本思想是使用凭证提供者,EMRFS通过凭证提供者访问S3存储桶中的对象。
    您可以更进一步,为本博客中创建的JAR参数化ARN for STS和bucket。

    请小心,它看起来像
    fs.s3n.awsAccessKeyId
    仅适用于通过
    s3n://bucket/file
    访问的文件。这可能不是系统从S3读取数据的方式。请参阅:。您的语句“首先,从S3读取数据(由于我的EMR群集位于同一帐户中,因此不需要凭据)”不太准确。EMR集群确实需要凭据才能访问AmazonS3内容。凭据通过与群集节点关联的角色传入。它提供对您自己的S3存储桶的访问权限。除了
    S3:GetObject
    权限外,您可能还需要对希望使用的存储桶授予
    S3:ListBucket
    权限。(如果你的桶是KMS加密的,别忘了KMS权限)。伙计,你救了我