运行 具有多个 S3 帐户的 EMR Spark

Running EMR Spark With Multiple S3 Accounts

我有一个 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 运气不好。

每一个returns一个错误:

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

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

解决方法其实很简单。

首先,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:*) 授予 EMR_EC2_DefaultRole 角色,该角色属于与策略中的 ACCOUNT-NUMBER 匹配的帐户,该帐户应该是EMR集群上线。授予此类权限时要小心——您可能只想授予 GetObject 权限,而不是授予所有 S3 权限。

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

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

使用 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。

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