web-dev-qa-db-ja.com

EMRの実行Spark複数のS3アカウントで

あるアカウントでS3からデータを読み取り、別のアカウントに書き込む必要があるEMR Sparkジョブがあります。
仕事を2つのステップに分けました。

  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=

clusterモードとclientモードの両方、およびspark-Shellを試しましたが運がありませんでした。

それらのそれぞれがエラーを返します:

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

解決策は実際には非常に簡単です。

まず、EMRクラスターには2つの役割があります。

これらのロールについては、次のように説明されています。 Amazon EMRのデフォルトのIAMロール

したがって、クラスターで起動された各EC2インスタンスにはEMR_EC2_DefaultRoleロールが割り当てられます。これにより、インスタンスメタデータサービスを介して一時的な認証情報を利用できるようになります。 (これがどのように機能するかの説明については、以下を参照してください: Amazon EC2のIAMロール 。)Amazon EMRノードは、これらの資格情報を使用して、S3、SNS、SQS、CloudWatch、DynamoDBなどのAWSサービスにアクセスします。

次に、EMR_EC2_DefaultRoleロールを介したアクセスを許可するには、他のアカウントのAmazonS3バケットにアクセス許可を追加する必要があります。これは、次のように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:*に一致するアカウント(EMRクラスターが起動されたアカウントである必要があります)に属するEMR_EC2_DefaultRoleロールにすべてのS3アクセス許可(ACCOUNT-NUMBER)を付与します。このようなアクセス許可を付与するときは注意してください。すべてのS3アクセス許可を付与するのではなく、GetObjectにのみアクセス許可を付与することをお勧めします。

これですべてです!他のアカウントのバケットは、EMRノードがEMR_EC2_DefaultRoleロールを使用しているため、EMRノードからのリクエストを受け入れるようになりました。

免責事項:アカウントAでバケットを作成し、アカウントBのロールに権限(上記のとおり)を割り当てることで、上記をテストしました。 EC2インスタンスは、そのロールでAccount-Bで起動されました。 AWSコマンドラインインターフェイス(CLI) を介してEC2インスタンスからバケットにアクセスできました。私はEMR内でそれをテストしませんでした、しかしそれは同じように動作するはずです

17
John Rotenstein

sparkを使用すると、assume roleを使用して別のアカウントのs3バケットにアクセスできますが、他のアカウントでIAM Roleを使用できます。これにより、他のアカウント所有者がに提供されたアクセス許可を管理しやすくなります。 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の使用はまだ試していません。

2
WaterK

コンピューティングノードにIAMロールを割り当てる必要があると思います(おそらくすでにこれを行っています)。次に、「リモート」アカウントのIAMを介してそのロールへのクロスアカウントアクセスを許可します。詳細については、 http://docs.aws.Amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html を参照してください。

0
easel