运行 具有多个 S3 帐户的 EMR Spark
Running EMR Spark With Multiple S3 Accounts
我有一个 EMR Spark 作业需要在一个帐户上从 S3 读取数据并写入另一个帐户。
我把我的工作分成两步。
从 S3 读取数据(不需要凭据,因为我的 EMR 集群在同一个帐户中)。
读取步骤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=
我已经尝试了 cluster 和 client 模式以及 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集群有两个角色:
- 一个服务角色 (
EMR_DefaultRole
) 授予 EMR 服务权限(例如启动 Amazon EC2 实例)
- 附加到集群中启动的 EC2 实例的 EC2 角色 (
EMR_EC2_DefaultRole
),使它们能够访问 AWS 凭据(参见 Using an IAM Role to Grant Permissions to Applications Running on Amazon EC2 Instances)
这些角色的解释如下: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。
我有一个 EMR Spark 作业需要在一个帐户上从 S3 读取数据并写入另一个帐户。
我把我的工作分成两步。
从 S3 读取数据(不需要凭据,因为我的 EMR 集群在同一个帐户中)。
读取步骤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=
我已经尝试了 cluster 和 client 模式以及 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集群有两个角色:
- 一个服务角色 (
EMR_DefaultRole
) 授予 EMR 服务权限(例如启动 Amazon EC2 实例) - 附加到集群中启动的 EC2 实例的 EC2 角色 (
EMR_EC2_DefaultRole
),使它们能够访问 AWS 凭据(参见 Using an IAM Role to Grant Permissions to Applications Running on Amazon EC2 Instances)
这些角色的解释如下: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。