【问题标题】:Running EMR Spark With Multiple S3 Accounts使用多个 S3 账户运行 EMR Spark
【发布时间】:2017-03-14 20:31:25
【问题描述】:

我有一个 EMR Spark 作业,需要从一个帐户的 S3 读取数据并写入另一个帐户。
我把我的工作分成两个步骤。

  1. 从 S3 读取数据(不需要凭据,因为我的 EMR 集群在同一个账户中)。

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

我尝试设置hadoopConfiguration:

sc.hadoopConfiguration.set("fs.s3n.awsAccessKeyId", "<your access key>")
sc.hadoopConfiguration.set("fs.s3n.awsSecretAccessKey","<your secretkey>")

并导出集群上的密钥:

$ export AWS_SECRET_ACCESS_KEY=
$ export AWS_ACCESS_KEY_ID=

我尝试了 clusterclient 模式以及 spark-shell 都没有运气。

每个都返回一个错误:

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

【问题讨论】:

  • 小心——看起来fs.s3n.awsAccessKeyId 只适用于通过s3n://bucket/file 访问的文件。这可能不是您的系统从 S3 读取的方式。请参阅:Hadoop-AWS module: Integration with Amazon Web Services
  • 您的说法“首先,从 S3 读取数据(不需要凭据,因为我的 EMR 集群在同一个帐户中)”不太准确。 EMR 集群确实需要凭证才能访问 Amazon S3 内容。凭据通过与集群节点关联的角色传入。它允许访问您自己的 S3 存储桶。

标签: apache-spark amazon-s3 amazon-emr


【解决方案1】:

我认为您需要为您的计算节点分配一个 IAM 角色(您可能已经这样做了),然后通过“远程”账户上的 IAM 授予对该角色的跨账户访问权限。详情请见http://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html

【讨论】:

    【解决方案2】:

    解决方案其实很简单。

    首先,EMR 集群有两个作用:

    这些角色解释在:Default IAM Roles for Amazon EMR

    因此,集群中启动的每个 EC2 实例都被分配了EMR_EC2_DefaultRole 角色,这通过实例元数据服务提供临时凭证。 (有关其工作原理的说明,请参阅:IAM Roles for Amazon EC2。)Amazon EMR 节点使用这些凭证来访问 AWS 服务,例如 S3、SNS、SQS、CloudWatch 和 DynamoDB。

    其次,您需要向其他账户中的 Amazon S3 存储桶添加权限,以允许通过 EMR_EC2_DefaultRole 角色进行访问。这可以通过向 S3 存储桶(此处命名为 other-account-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:*) 授予属于与策略中的ACCOUNT-NUMBER 匹配的帐户的EMR_EC2_DefaultRole 角色,该帐户应该是启动 EMR 集群的帐户。授予此类权限时要小心——您可能只想授予 GetObject 权限,而不是授予所有 S3 权限。

    就是这样!另一个帐户中的存储桶现在将接受来自 EMR 节点的请求,因为它们使用的是EMR_EC2_DefaultRole 角色。

    免责声明:我通过在 Account-A 中创建存储桶并将权限(如上所示)分配给 Account-B 中的角色来测试上述内容。在 Account-B 中以该角色启动了一个 EC2 实例。我能够通过AWS Command-Line Interface (CLI) 从 EC2 实例访问存储桶。我确实没有在 EMR 中对其进行测试,但是它应该以相同的方式工作。

    【讨论】:

    • 除了s3:GetObject 权限之外,您可能还需要对您希望使用的存储桶授予s3:ListBucket 权限。 (如果您的存储桶是 KMS 加密的,请不要忘记 KMS 权限)。
    • 朋友,你救了我
    【解决方案3】:

    使用 spark,您还可以使用承担角色访问另一个账户中的 s3 存储桶,但使用另一个账户中的 IAM 角色。这使其他帐户所有者可以更轻松地管理提供给 spark 作业的权限。通过 s3 存储桶策略管理访问可能会很痛苦,因为访问权限分布到多个位置,而不是全部包含在单个 IAM 角色中。

    这里是hadoopConfiguration

    "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>>"
    

    外部 ID 也可以用作密码:

    "spark.hadoop.fs.s3a.stsAssumeRole.externalId" -> "GUID created by other account owner"
    

    我们在上面使用数据块尚未尝试使用 EMR。

    【讨论】:

      【解决方案4】:

      为了控制对资源的访问,通常将 IAM 角色作为标准做法进行管理。当您想要访问不同账户中的资源时,使用假设角色。如果您或您的组织遵循相同的做法,那么您应该关注https://aws.amazon.com/blogs/big-data/securely-analyze-data-from-another-aws-account-with-emrfs/。 这里的基本思想是使用 EMRFS 获得访问权限的凭证提供程序来访问 S3 存储桶中的对象。 您可以更进一步,为本博客中创建的 JAR 参数化 STS 和存储桶的 ARN。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-01
        • 2016-08-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-20
        相关资源
        最近更新 更多